/**
 * 如果要直接为对象的所有属性开发一个校验器可能很快就会让代码结构变得臃肿，
 * 使用 Proxy 则可以将校验器从核心逻辑分离出来自成一体
 *
 */


/**
 * https://www.jianshu.com/p/c2a1aa2e2b14
 * 通过校验器和主逻辑的分离，你可以无限扩展 personValidators 校验器的内容，
 * 而不会对相关的类或函数造成直接破坏。
 * @param target
 * @param validator
 * @returns {*}
 */
function createValidator(target, validator) {
    return new Proxy(target, {
        _validator: validator,
        set(target, key, value, proxy) {
            if (target.hasOwnProperty(key)) {
                let validator = this._validator[key];
                if (validator(value)) {
                    return Reflect.set(target, key, value, proxy);
                } else {
                    throw Error(`Cannot set ${key} to ${value}. Invalid.`);
                }
            } else {
                throw Error(`${key} is not a valid property`)
            }
        }
    });
}

const personValidators = {
    name(val) {
        return typeof val === 'string';
    },
    age(val) {
        return typeof val === 'number' && val > 18;
    }
}
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
        return createValidator(this, personValidators);
    }
}

const bill = new Person('Bill', 25);

// 以下操作都会报错
// bill.name = 0; // Error: Cannot set name to 0. Invalid.
// bill.age = 'Bill'; // Error: Cannot set age to Bill. Invalid.
bill.age = 15;  // Error: Cannot set age to 15. Invalid.


